function hxs = hxsingle(inp)
% hxsingle  - transform a single from/into a readable string
%
% singles cannot be printed in their native "precision". hxsingle
% gives a more memory based representation so as to store the
% exact value of a number
%
% FORMAT:       hxstring = hxsingle(singles)
%         or    singles  = hxsingle(hxstring)
%
% Input fields:
%
%       singles     an array of type single (only real numbers)
%                   a non-linear array will be linearized (:)'
%       hxstring    a 1xN char representation prior created with
%                   this function
%
% Output fields:
%
%       hxstring    the resulting string from a call to hxsingle
%       singles     an 1xN single array, transformed back from a
%                   string representation
%
% See also any2ascii.

% Version:  v0.7f
% Build:    8110521
% Date:     Nov-05 2008, 9:00 PM CET
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

persistent hxs_hxr;
if isempty(hxs_hxr)
    hxs_hxr = [ ...
                nan * ones(1, 48) ...
                  0   1   2   3   4   5   6   7   8   9 nan nan nan nan nan nan ...
                nan  10  11  12  13  14  15 nan nan nan nan nan nan nan nan nan ...
                nan * ones(1, 16) ...
                nan  10  11  12  13  14  15 nan nan nan nan nan nan nan nan nan ...
                nan * ones(1,144) ...
              ];
end

% enough arguments ?
if nargin < 1
    error( ...
        'BVQXtools:TooFewArguments',...
        'Too few arguments. Try ''help %s''.',...
        mfilename ...
    );
end

inp = inp(:)';
if isa(inp, 'single')
    if isempty(inp)
        hxs = '';
        return;
    end
    inp = double(inp);
    ips = numel(inp);
    hxs = char(ones(1,8 * ips) * '0');
    for ipc = 1:ips
        ipn = inp(ipc);
        if isnan(ipn)
            hxs(8*ipc-7:8*ipc) = 'ffc00000';
            continue;
        elseif isinf(ipn)
            if ipn == -Inf
                hxs(8*ipc-7:8*ipc) = 'ff800000';
            else
                hxs(8*ipc-7:8*ipc) = '7f800000';
            end
            continue;
        elseif ipn == 0
            hxs(8*ipc-7:8*ipc) = '00000000';
            continue;
        end
        if ipn < 0
            isg = 2147483648;
            ipn = -ipn;
        else
            isg = 0;
        end
        exp = 127 + floor(log2(ipn));
        mnt = fix(ipn * pow2(150-exp)) - 2.^23;
        hxr = ['00000000' lower(dec2hex(isg + 2.^23 * exp + mnt))];
        hxs(8*ipc-7:8*ipc) = hxr(end-7:end);
    end
elseif ischar(inp)
    inp = inp(:)';
    ns  = floor(length(inp)/8);
    hxs = zeros(1,ns);
    for hxc = 1:ns
        ipp = lower(inp((hxc-1)*8+1:hxc*8));
        if strcmp(ipp, 'ffc00000')
            hxs(hxc) = NaN;
            continue;
        end
        ipi = hxs_hxr(min(double(ipp),255)+1);
        if any(isnan(ipi)) || ...
            all(ipi == 0)
            continue;
        end
        iex = 32*ipi(1)+2*ipi(2)+fix(ipi(3)/8);
        if iex > 255
            isg = -1;
            iex = iex - 256;
        else
            isg = 1;
        end
        imt = 1 + bitand(7,ipi(3))/8 + hex2dec(ipp(4:8))/2.^23;
        hxs(hxc) = isg * imt * 2.^(iex-127);
    end
    hxs = single(hxs);
else
    if isa(inp, 'double')
        error( ...
            'BVQXtools:BadArgument',...
            'Bad input class. Use hxdouble(...) instead.' ...
        );
    else
        error( ...
            'BVQXtools:BadArgument',...
            'Bad input class.' ...
        );
    end
end
